#include "stdafx.h"
#include "Exports.h"

//Proxies

MEMMAN_API void MmInitialize()
{
	_manager = new CMemMan();
	setlocale(LC_ALL, "");		//Default system locale, guess KIS' logger still uses same behavior
}

MEMMAN_API void MmDeInitialize()
{
	if(_manager)
	{
		delete _manager;
		_manager = NULL;
	}
}

MEMMAN_API void MmReInitialize()
{
	MmDeInitialize();
	MmInitialize();
}

MEMMAN_API bool MmIsInitialized()
{
#pragma warning (disable: 4800)
	retbool _manager;
#pragma warning (default: 4800)
}

MEMMAN_API unsigned GetThreadEventsCount(unsigned threadIdx, bool useFilter)
{
	return _manager->GetEventsCountForThread(threadIdx, useFilter);
}

MEMMAN_API unsigned GetThreadIndexForId(short threadId)
 {
	return _manager->GetThreadIndex(threadId);
 }

MEMMAN_API short GetThreadIdForIndex(unsigned threadIdx)
 {
	return _manager->GetTidForIndex(threadIdx);
 }

MEMMAN_API int GetEventTime(unsigned threadIdx, unsigned eventIdx, bool useFilter)
{
	return (int)(_manager->GetEventData(threadIdx, eventIdx, CMemMan::Time, useFilter));
}

MEMMAN_API char GetEventType(unsigned threadIdx, unsigned eventIdx, bool useFilter)
{
	return (char)(_manager->GetEventData(threadIdx, eventIdx, CMemMan::Type, useFilter));
}

MEMMAN_API char* GetEventService(unsigned threadIdx, unsigned eventIdx, bool useFilter)
{
	return _manager->GetEventData(threadIdx, eventIdx, CMemMan::Service, useFilter);
}

MEMMAN_API char* GetEventMessage(unsigned threadIdx, unsigned eventIdx, bool useFilter)
{
	return _manager->GetEventData(threadIdx, eventIdx, CMemMan::Message, useFilter);
}

MEMMAN_API void GetEventMessageEx(unsigned threadIdx, unsigned eventIdx, char* outBuffer, bool useFilter)
{
	_manager->ExpandEventMessage(GetEventMessage(threadIdx, eventIdx, useFilter), outBuffer);
}

MEMMAN_API void GetEventTimeEx(unsigned threadIdx, unsigned eventIdx, char* outBuffer, bool useFilter)
{
	_manager->ExpandEventTime(GetEventTime(threadIdx, eventIdx, useFilter), outBuffer);
}


MEMMAN_API unsigned GetThreadsCountTotal()
{
	return _manager->GetThreadsCount();
}

MEMMAN_API void AddString(LPCSTR data)
{
	_manager->PushLine((char*)data);
}

MEMMAN_API unsigned AddBlock(LPSTR data, unsigned length)
{
	return _manager->PushBulk((char*)data, length);
}

MEMMAN_API void FilterAddType(char* data)
{
	_manager->AddFilter(data, CMemMan::Type);
}

MEMMAN_API void FilterAddService(char* data)
{
	_manager->AddFilter(data, CMemMan::Service);
}

MEMMAN_API void FilterClear()
{
	_manager->ClearFilter();
}

MEMMAN_API void FilterApply(unsigned threadIdx)
{
	_manager->ApplyFilter(threadIdx);
}

MEMMAN_API unsigned FilterGetServicesCount()
{
	return _manager->GetServicesCount();
}

MEMMAN_API char* FilterGetServiceById(unsigned idx)
{
	return _manager->GetServiceById(idx);
}

MEMMAN_API unsigned FilterGetActiveThreadIdx()
{
	return _manager->GetFilteredThreadIdx();
}

 //Raw implementation

MEMMAN_API unsigned ParseBack(LPCSTR data, unsigned size)
{
	char* ptr = (char*)data + size - 1;
	char* ptrCopy = ptr;
	while (*ptr && *ptr != 10)
		ptr--;
#ifdef _X64
	return (unsigned)(ptrCopy - ptr);
#else
	return ptrCopy - ptr;
#endif
}

MEMMAN_API unsigned long long TermSearch(unsigned long long searchPos, int direction, char* term, bool shiftAtFirstIteration)
{
	unsigned tIdx, eIdx, tCount, eCount, threadIdx, eventIdx;
	threadIdx = searchPos >> 32;
	eventIdx = searchPos & 0xFFFFFFFF;
	tIdx = threadIdx;
	eIdx = eventIdx;
	tCount = GetThreadsCountTotal();
	eCount = GetThreadEventsCount(tIdx, true);
	while (true)
	{
		if(shiftAtFirstIteration)
		{
			if(eIdx == 0 && direction == -1)
			{
				do
				{
					tIdx = ((tIdx == 0) ? tCount - 1 : tIdx -1);
					eCount = GetThreadEventsCountWihPossibleFilter(tIdx);
				} while (eCount == 0 && tIdx != threadIdx); //filtered
				eIdx = eCount - 1;
			}
			else if(direction == 1 && (eIdx + 1) >= eCount)
			{
				do
				{
					tIdx = ((tIdx + 1 == tCount) ? 0 : tIdx + 1);
					eCount = GetThreadEventsCountWihPossibleFilter(tIdx);
				} while (eCount == 0 && tIdx != threadIdx); //filtered
				eIdx = 0;
			}
			else
				eIdx += direction;
			if(tIdx == threadIdx && eIdx == eventIdx)	//made whole round
				return 0xFFFFFFFFFFFFFFFF;				//unsigned -1 ;-p
		}
		else
		{
			shiftAtFirstIteration = true;
			if(eCount <= eIdx)                          //we just switched filter on
				continue;
		}
		GetEventMessageEx(tIdx, eIdx, searchBuffer, true);
		for (char *p = searchBuffer; *p; p++) 
			*p = tolower(*p);						//searchBuffer.ToLower(); setLocale above changes impl.
		if(strstr(searchBuffer, term))
			return ((long long)tIdx << 32) + eIdx;
	}
}

MEMMAN_API bool FilterIsActive()
{
	return FilterGetActiveThreadIdx() != 0xFFFFFFFF;
}

//"Private" functions for raw impl

unsigned GetThreadEventsCountWihPossibleFilter(unsigned threadIdx)
{
	if(FilterIsActive()) //IsFiltered
		FilterApply(threadIdx);
	return GetThreadEventsCount(threadIdx, true);
}

